﻿using NUnit.Framework;
using Silversocial.Client.Modules.Tests.Stubs;
using Silverstone;

namespace Silversocial.Client.Modules.Tests
{
    [TestFixture]
    public class LoginViewModelTester
    {
        private LoginViewStub loginViewStub;
        private AppShellStub shellStub;
        private LoginDataProviderStub dataProviderStub;
        private LoginViewModel viewModel;

        [SetUp]
        public void SetUp()
        {
            this.shellStub = new AppShellStub();
            this.dataProviderStub = new LoginDataProviderStub();
            this.viewModel = new LoginViewModel(shellStub, dataProviderStub);

            this.loginViewStub = new LoginViewStub();
            ((IViewModel) this.viewModel).SetView(this.loginViewStub);
        }

        [Test]
        public void Login_WithoutUsernameAndPassword_CannotExecute()
        {
            Assert.IsFalse(this.viewModel.Login.CanExecute(null));
        }

        [Test]
        public void Login_WithUsernameAndPassword_CanExecute()
        {
            // Arrange
            this.viewModel.User.Username = "abc";
            this.viewModel.User.Password = "abc";

            // Assert
            Assert.IsTrue(this.viewModel.Login.CanExecute(null));
        }

        [Test]
        public void Login_BeforeCompleted_IsLoggingInIsTrue()
        {
            // Act
            this.viewModel.Login.Execute(null);

            // Assert
            Assert.IsTrue(this.viewModel.IsLoggingIn);
        }

        [Test]
        public void Login_AfterCompleted_IsLoggingInIsFalse()
        {
            // Act
            this.viewModel.Login.Execute(null);
            this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(false));

            // Assert
            Assert.IsFalse(this.viewModel.IsLoggingIn);
        }

        [Test]
        public void Login_AfterCompleted_RaisesCanExecuteChangedEvent()
        {
            // Arrange
            bool canExecuteChangedCalled = false;
            this.viewModel.Login.CanExecuteChanged +=
                delegate { canExecuteChangedCalled = true; };

            // Act
            this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(false));

            // Assert
            Assert.IsTrue(canExecuteChangedCalled);
        }

        [Test]
        public void Login_WhilstLoggingIn_CannotExecute()
        {
            // Arrange
            this.viewModel.User.Username = "abc";
            this.viewModel.User.Password = "abc";

            // Act
            this.viewModel.IsLoggingIn = true;

            // Assert
            Assert.IsFalse(this.viewModel.Login.CanExecute(null));
        }

        [Test]
        public void Login_Always_CallsValidateUserOnDataProvider_WithCorrectUser()
        {
            // Arrange
            User userSentToDataProvider = null;
            this.dataProviderStub.ValidateUser += 
                u => userSentToDataProvider = u;
            
            // Act
            this.viewModel.Login.Execute(null);

            // Assert
            Assert.AreEqual(this.viewModel.User, userSentToDataProvider);
        }

        [Test]
        public void Login_WithInvalidDetails_CallsLoginUnsuccessfulOnView()
        {
            // Arrange
            this.dataProviderStub.ValidateUser +=
                u => this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(false));
            bool loginUnsuccessfulCalledOnView = false;
            this.loginViewStub.LoginUnsuccessful +=
                () => loginUnsuccessfulCalledOnView = true;

            // Act
            this.viewModel.Login.Execute(null);

            // Assert
            Assert.IsTrue(loginUnsuccessfulCalledOnView);
        }

        [Test]
        public void Login_WithValidDetails_SetsFriendListViewOnShell()
        {
            // Arrange
            this.dataProviderStub.ValidateUser += 
                u => this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(true));

            // Act
            this.viewModel.Login.Execute(null);

            // Assert
            Assert.AreEqual(typeof(IFriendListView), this.shellStub.TypeNavigatedTo);
        }

        [Test]
        public void Login_WithValidDetails_SetsUserOnShell()
        {
            // Arrange
            this.dataProviderStub.ValidateUser +=
                u => this.dataProviderStub.RaiseValidateUserCompleted(new ValidateUserCompletedEventArgs(true));

            // Act
            this.viewModel.Login.Execute(null);

            // Assert
            Assert.AreEqual(this.viewModel.User, this.shellStub.User);
        }

        [Test]
        public void Register_Always_SetsRegisterViewOnShell()
        {
            // Act
            this.viewModel.Register.Execute(null);

            // Assert
            Assert.AreEqual(typeof(IRegisterView), this.shellStub.TypeNavigatedTo);            
        }
    }
}